/*
 * $Id: string_strvec.c,v 1.9 2005-12-11 13:25:34 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/wstring.h>
#else
#include <xp/bas/string.h>
#endif

#include <xp/bas/memory.h>

xp_vstr_t* xp_vstr_open (xp_vstr_t* vec)
{
	if (vec == XP_NULL) {
		vec = (xp_vstr_t*)xp_malloc(xp_sizeof(xp_vstr_t));
		if (vec == XP_NULL) return XP_NULL;
		vec->__dynamic = xp_true;
	}
	else vec->__dynamic = xp_false;

	vec->buffer = vec->buffer_space;
	vec->buffer_capacity = xp_countof(vec->buffer_space);
	vec->buffer_ubound = 0;

	vec->vector = vec->vector_space;
	vec->vector_capacity = xp_countof(vec->vector_space) - 1;
	vec->vector_ubound = 0;
	vec->vector[0] = XP_NULL;

	return vec;
}

void xp_vstr_close (xp_vstr_t* vec)
{
	if (vec->vector_capacity > xp_countof(vec->vector_space) - 1) 
		xp_free (vec->vector);
	if (vec->buffer_capacity > xp_countof(vec->buffer_space))
		xp_free (vec->buffer);
	if (vec->__dynamic) xp_free (vec);
}

void xp_vstr_clear (xp_vstr_t* vec)
{
	if (vec->vector_capacity > xp_countof(vec->vector_space) - 1)  {
		xp_free (vec->vector);
		vec->vector = vec->vector_space;
		vec->vector_capacity = xp_countof(vec->vector_space) - 1;
		vec->vector_ubound = 0;
		vec->vector[0] = XP_NULL;
	}
	if (vec->buffer_capacity > xp_countof(vec->buffer_space)) {
		xp_free (vec->buffer);
		vec->buffer = vec->buffer_space;
		vec->buffer_capacity = xp_countof(vec->buffer_space);
		vec->buffer_ubound = 0;
	}
}

int xp_vstr_append (xp_vstr_t* vec, const xp_char_t* str)
{
	const xp_char_t* p;
	xp_size_t i;

	if (vec->vector_ubound >= vec->vector_capacity) {
		xp_char_t** space;

		if (vec->vector_capacity < xp_countof(vec->vector_space)) {
			space = (xp_char_t**)xp_malloc (
				xp_sizeof(xp_char_t**) * (vec->vector_capacity * 2 + 1));
			if (space == XP_NULL) return -1;

			xp_memcpy (space, vec->vector, 
				vec->vector_ubound * xp_sizeof(xp_char_t**));
		}
		else {
			space = (xp_char_t**)xp_realloc (vec->vector,
				xp_sizeof(xp_char_t**) * (vec->vector_capacity * 2 + 1));
			if (space == XP_NULL) return -1;
		}

		vec->vector = space;
		vec->vector_capacity = vec->vector_capacity * 2;
	}
	vec->vector[vec->vector_ubound++] = &vec->buffer[vec->buffer_ubound];
	vec->vector[vec->vector_ubound] = XP_NULL;

	for (p = str; ;p++) {
		if (vec->buffer_ubound >= vec->buffer_capacity) {
			xp_char_t* space;

			space = (xp_char_t*)xp_malloc (
				xp_sizeof(xp_char_t*) * (vec->buffer_capacity * 2));	
			if (space == XP_NULL) {
				vec->vector_ubound--;
				return -1;
			}

			xp_memcpy (space, vec->buffer, 
				vec->buffer_ubound * xp_sizeof(xp_char_t));

			for (i = 0; i < vec->vector_ubound; i++) {
				vec->vector[i] = space + (vec->vector[i] - vec->buffer);
			}	

			if (vec->buffer_capacity > xp_countof(vec->buffer_space)) {
				xp_free (vec->buffer);
			}
			vec->buffer = space;
			vec->buffer_capacity = vec->buffer_capacity * 2;
		}

		vec->buffer[vec->buffer_ubound++] = *p;
		if (*p == XP_CHAR('\0')) break;
	}

	return 0;
}

